import datetime
import random
from dataclasses import dataclass

def getRandomColorEncodedStr() -> str:
    MIN_COLOR_CODE = 0
    MAX_COLOR_CODE = 0xFFFFFF

    return '#{:0>6x}'.format(random.randint(MIN_COLOR_CODE, MAX_COLOR_CODE))


def parseDateToStr(date : datetime.date) -> str:
    return date.strftime("%Y 年 %m 月 %d 日")


def parseDatetimeToOnlyTimeStr(time_value : datetime.datetime) -> str:
    return time_value.strftime("%H:%M")


def getDatesDiff(date_1 : datetime.date, date_2 : datetime.date) -> int:
    return abs((date_1 - date_2).days)

@dataclass
class DataHelper():
    date : datetime.date
    city : str
    weather : str
    current_temperature : float
    day_max_temperature : float
    day_min_temperature : float
    wind_direction : str
    air_quality : str
    sun_raise_time : datetime.datetime
    sun_set_time : datetime.datetime
    date_in_love : datetime.date
    birthday : datetime.date
    suggestion : str
    crap : str


    def __post_init__(self):
        self.checkParameters()


    def checkParametersType(self):
        assert isinstance(self.date, datetime.date)
        assert isinstance(self.city, str)
        assert isinstance(self.weather, str)
        assert isinstance(self.current_temperature, float)
        assert isinstance(self.day_max_temperature, float)
        assert isinstance(self.day_min_temperature, float)
        assert isinstance(self.wind_direction, str)
        assert isinstance(self.air_quality, str)
        assert isinstance(self.sun_raise_time, datetime.datetime)
        assert isinstance(self.sun_set_time, datetime.datetime)
        assert isinstance(self.date_in_love, datetime.date)
        assert isinstance(self.birthday, datetime.date)
        assert isinstance(self.suggestion, str)
        assert isinstance(self.crap, str)


    def checkParameters(self):
        self.checkParametersType()
        assert self.current_temperature <= self.day_max_temperature
        assert self.day_min_temperature <= self.current_temperature
        assert self.date == self.sun_raise_time.date()
        assert self.date == self.sun_set_time.date()
        assert self.date >= self.date_in_love


    def colorize(self, data : dict[str, dict]):
        for key in data.keys():
            data[key]['color'] = getRandomColorEncodedStr()


    def getBirthdayLeftDays(self) -> int:
        birthday_this_year = datetime.date(self.date.year, self.birthday.month, self.birthday.day)
        if birthday_this_year > self.date:
            return getDatesDiff(self.date, birthday_this_year)
        else:
            birthday_next_year = datetime.date(self.date.year + 1, self.birthday.month, self.birthday.day)
            return getDatesDiff(self.date, birthday_next_year)


    def getLoveLastDays(self) -> int:
        return getDatesDiff(self.date, self.date_in_love)


    def buildupRawData(self) -> dict:
        data = {}
        def insertValue(field_name : str, value : str):
            assert isinstance(value, str), 'Data fields must take str value.'
            data[field_name] = {'value' : value}

        insertValue('area', self.city)
        insertValue('calendar', parseDateToStr(self.date))
        insertValue('weather', '今日天气：{}'.format(self.weather))
        insertValue('wind', self.wind_direction)
        insertValue('current_temperature', '当前气温：{:.1f}℃'.format(self.current_temperature))
        insertValue('min_temperature', '最低气温：{:.1f}℃'.format(self.day_min_temperature))
        insertValue('max_temperature', '最低气温：{:.1f}℃'.format(self.day_max_temperature))
        insertValue('air', '空气质量：{}'.format(self.air_quality))
        insertValue('sun_go', '日出时间：{}'.format(parseDatetimeToOnlyTimeStr(self.sun_raise_time)))
        insertValue('sun_out', '日落时间：{}'.format(parseDatetimeToOnlyTimeStr(self.sun_set_time)))
        insertValue('love_days', "今天是我们恋爱的第{}天".format(self.getLoveLastDays()))
        insertValue('birthday_left', "距离宝贝的生日还有{}天".format(self.getBirthdayLeftDays()))
        insertValue('suggestion', "今天建议：{}".format(self.suggestion))
        insertValue('words', self.crap)

        return data


    def BuildData(self, if_colorize = True) -> dict[str, dict]:
        data = self.buildupRawData()

        if if_colorize:
            self.colorize(data)

        return data